from flask import Flask, render_template, request, redirect, Blueprint, send_file, g
from forms import AccessCommandForm, SharedFileForm, SharedFileAnonymityForm
from models import User, File, SharedFile
import Encryption_and_decryption as ed

share_file = Blueprint("share_file", __name__, url_prefix="/shared_file")


# 文件分享 访问权限检验
@share_file.route("/<string:JWT>", methods=["GET", "POST"])
def share_file_(JWT):
    # JWT 编码 URL 完整性校验
    def jwt_verify(JWT):
        import jwt

        jwt_json = jwt.jwt_to_json(JWT)
        shared_file_ = SharedFile.query.get(jwt_json["share_id"])
        # 解密JWT信息 对照数据库进行验证
        if not shared_file_ or int(jwt_json["file_id"]) != shared_file_.file_id:
            return False
        elif jwt_json["date_limit"]:
            from datetime import date

            date_limit = date.fromisoformat(jwt_json["date_limit"])
            if date_limit < date.today():
                return False
        elif shared_file_.counts_flag and shared_file_.counts_limit <= 0:
            return False

        return jwt_json

    jwt_json = jwt_verify(JWT)
    if not jwt_json:
        error = "分享不存在，已过期或下载次数达到上限"
        return render_template("share_file.html", error=error)

    shared_file = SharedFile.query.get(jwt_json["share_id"])
    file_ = File.query.get(jwt_json["file_id"])
    user_ = User.query.get(file_.user_id)

    # 判断是否存在提取码验证
    if request.method == "GET":
        # 存在提取码验证
        if shared_file.access_com:
            form = AccessCommandForm()
            return render_template("share_file.html", form=form)
        # 不存在 直接跳转 文件下载页
        elif not shared_file.access_com:
            if not g.user:
                form = SharedFileAnonymityForm(
                    file_name=file_.file_name, user_name=user_.username
                )
            else:
                form = SharedFileForm(
                    file_name=file_.file_name, user_name=user_.username
                )
            return render_template("share_file.html", form=form)

    # 分享文件的下载方法
    def shared_file_download(user_, file_):
        from config import storage_path

        file_path = storage_path + str(user_.user_id) + "/" + file_.file_name
        with open(file_path, "rb") as file:
            file_info = file.read()

        # --- 校验密文签名 --- #
        print("public_key", file_.public_key)
        if not ed.Hash_verify(file_.public_key, file_.file_signature, file_info):
            error = "文件签名校验失败，完整性缺失"
            return render_template("share_file.html", error=error)

        # 调用解密数据库内文件 解密密文出字节表示的明文
        ctext = ed.file_download_decryption(user_.hash_password, file_info)
        # 调取数据库中的静态散列值
        static_hash = file_.static_hash
        # 输入待分享的明文，生成随机数，并根据随机数派生出对称密钥
        r_e = ed.file_share_encryption(ctext)
        random = r_e[0]
        # 根据随机数派生的密钥生成新密文
        share_e = r_e[1]
        # 提供分享密文已登录用户的解密下载
        share_d = ed.file_share_decryption(random, share_e)

        # 对文件生成HASH值，并使用私钥加密进行签名，生成不可伪造的散列值
        user_ = User.query.get(file_.user_id)
        # 根据 用户密码 用户盐值 分享密文 生成 HMAC 数字签名
        p_h = ed.Hash_get(user_.hash_password, user_.user_salt, share_e)
        public_key = p_h[0]
        share_signature = p_h[1]

        # 待加入登录状态判断
        # --- #
        share_json = {
            "file_name": file_.file_name,
            "ctext": ctext,
            "share_e": share_e,
            "share_signature": share_signature,
            "static_hash": static_hash,
        }

        return share_json

    if request.method == "POST":
        form = AccessCommandForm(request.form)
        if not g.user:
            share_form = SharedFileAnonymityForm(
                file_name=file_.file_name, user_name=user_.username
            )
        else:
            share_form = SharedFileForm(
                file_name=file_.file_name, user_name=user_.username
            )

        # 判断是否存在提取码验证
        if form.access_com.data:
            # 验证口令哈希值与数据库密文进行对照
            if not ed.check_password_get(form.access_com.data, shared_file.access_com):
                error = "提取码错误"
                return render_template("share_file.html", form=form, com_error=error)
            # 提取码验证通过
            form = share_form
            return render_template("share_file.html", form=form)

        # 不存在提取码验证 或 提取码验证通过后 跳转文件信息页
        form = share_form

        if form.validate_on_submit():
            remain_counts = shared_file.counts_limit
            # 如果存在下载次数限制
            if shared_file.counts_flag:
                if remain_counts > 0:
                    # 更新 剩余可下载次数
                    from database import db

                    shared_file.counts_limit -= 1
                    db.session.commit()
                else:
                    error = "分享下载次数已达上限"
                    return render_template("share_file.html", form=form, error=error)

        # 调用文件下载功能
        import os
        from flask import make_response
        from urllib.parse import quote

        filename = file_.file_name
        file_name = quote(filename)
        share_json = shared_file_download(user_, file_)
        filename = os.path.splitext(file_name)[0]
        extension = os.path.splitext(file_name)[1]

        if g.user and form.download:
            response = make_response(share_json["ctext"])
            response.headers.add(
                "Content-Disposition", "attachment", filename=file_name
            )
            return response

        elif form.download_e.data:
            response = make_response(share_json["share_e"])
            response.headers.add(
                "Content-Disposition",
                "attachment",
                filename=filename + "_encrypted" + extension,
            )
            return response

        elif form.download_s.data:
            response = make_response(share_json["share_signature"])
            response.headers.add(
                "Content-Disposition",
                "attachment",
                filename=filename + "_signature.txt",
            )
            return response

        elif form.download_hash.data:
            response = make_response(share_json["static_hash"])
            response.headers.add(
                "Content-Disposition", "attachment", filename=filename + "_hash.txt"
            )
            return response

        return render_template("share_file.html", form=form)
